package main

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

/**
golang中sync包实现了两种锁Mutex(互斥锁)和RWMutex(读写锁)
【1】互斥锁
	具中Mutex为互斥锁，Lock()加锁，Unlock()解锁，使用Lock()加锁后，便不能再次对其进行加锁，直到利用Unlock()解锁对其解锁后，才能再次加锁，
	适用于读写不确定场景，即读写次数没有明显的区别。 性能、效率相对来说比较低
【2】读写锁
	RWMutex是一个读写锁，其经常用于读次数远远多于写次数的场景，
	在读的时候，数据之间不产生影响，写和读之间才会产生影响
**/

func main() {
	test()
	//test2()
}

var wg sync.WaitGroup
var lock sync.Mutex
var lockWrite sync.RWMutex
var totalNum int = 0
var totalNum2 int = 0

func test2() {
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go read()
	}
	wg.Add(1)
	go write()
	wg.Wait()
	fmt.Println(" end ")
}

func read() {
	defer wg.Done()
	lockWrite.RLock()
	defer lockWrite.RUnlock()
	fmt.Println("开始读数据")
	time.Sleep(time.Second)
	fmt.Println("读取数据完成")
}

func write() {
	defer wg.Done()
	lockWrite.Lock()
	defer lockWrite.Unlock()
	fmt.Println("开始写数据--write")
	time.Sleep(time.Second)
	fmt.Println("写入数据完成--write")
}

// 互斥锁的写法
func test() {
	wg.Add(2)
	go sub()
	go add()
	wg.Wait()
	fmt.Println(" totalNum = " + strconv.Itoa(totalNum))
}

func add() {
	defer wg.Done()
	lock.Lock()
	defer lock.Unlock()
	fmt.Println("开始执行add", totalNum)
	for i := 0; i < 1000000000; i++ {
		totalNum++
	}
}

func sub() {
	defer wg.Done()
	lock.Lock()
	defer lock.Unlock()
	fmt.Println("开始执行sub", totalNum)
	for i := 0; i < 1000000000; i++ {
		totalNum--
	}
}
